#include "Avalon/Serialization/Deserializer.hpp"

using namespace Avalon;
using namespace Avalon::Serialization;
using namespace boost;
using namespace std;

namespace {
  void* NullConstructor() {
    return NULL;
  }

  shared_ptr<void> NullSharedConstructor() {
    return shared_ptr<void>();
  }
}

Deserializer::~Deserializer() {}

bool Deserializer::IsReceiving() {
  return true;
}

DataShuttle::ConstructorType Deserializer::FindConstructor() {
  int typeId;
  Shuttle("type_id", typeId);
  if(typeId == -1) {
    return &NullConstructor;
  } else if(typeId >= static_cast<int>(m_constructors.size())) {
    string typeName;
    Shuttle("type_name", typeName);
    map<string, ConstructorType>::const_iterator constructorIterator =
      GetTypeNameToConstructor().find(typeName);
    if(constructorIterator == GetTypeNameToConstructor().end()) {
      BOOST_THROW_EXCEPTION(SerializationException(
        "Unknown type: " + typeName));
    }
    m_constructors.push_back(constructorIterator->second);
    return constructorIterator->second;
  } else if(typeId < -1) {
    BOOST_THROW_EXCEPTION(SerializationException("Unknown type."));
  }
  return m_constructors[typeId];
}

DataShuttle::SharedConstructorType Deserializer::FindSharedConstructor() {
  int typeId;
  Shuttle("type_id", typeId);
  if(typeId == -1) {
    return &NullSharedConstructor;
  } else if(typeId >= static_cast<int>(m_sharedConstructors.size())) {
    string typeName;
    Shuttle("type_name", typeName);
    map<string, SharedConstructorType>::const_iterator constructorIterator =
      GetTypeNameToSharedConstructor().find(typeName);
    if(constructorIterator == GetTypeNameToSharedConstructor().end()) {
      BOOST_THROW_EXCEPTION(SerializationException(
        "Unknown type: " + typeName));
    }
    m_sharedConstructors.push_back(constructorIterator->second);
    return constructorIterator->second;
  } else if(typeId < -1) {
    BOOST_THROW_EXCEPTION(SerializationException("Unknown type."));
  }
  return m_sharedConstructors[typeId];
}
